use std::{fs::File, sync::Arc};
use crate::{utils, errors::GitError, git::hash::Hash};
use super::{Pack, cache::PackObjectCache};
use std::convert::TryFrom;
use std::cmp::Ordering;
impl Eq for Pack{}
impl Ord for Pack {
    fn cmp(&self, other: &Self) -> Ordering {
        let a = self.pack_file.metadata().unwrap().created().unwrap() ;
        let b = other.pack_file.metadata().unwrap().created().unwrap();
        if a==b{
            return Ordering::Equal;
        } else if a>b{
            return Ordering::Greater;
        } else {
            return Ordering::Less;
        }
    }
}

impl PartialOrd for Pack {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for Pack {
    fn eq(&self, other: &Self) -> bool {
        let a = self.pack_file.metadata().unwrap().created().unwrap() ;
        let b = other.pack_file.metadata().unwrap().created().unwrap();
        a==b
    }
}

impl Pack{
    /// Decode the `.pack` file with the object cache 
    #[allow(unused)]
    pub fn decode_with_cache(&self,cache:&mut PackObjectCache) -> Result<Self, GitError> {
        let mut pack_file = File::open(self.pack_file.clone()).unwrap();
        // Check the Header of Pack File
        let mut _pack = Self::check_header(&mut pack_file)?;

        for _ in 0.._pack.number_of_objects {
            //update offset of the Object
            let offset = utils::get_offset(&mut pack_file).unwrap();
            //Get the next Object by the Pack::next_object() func
            let object = Pack::next_object(&mut pack_file, offset, cache)?;
            // Larger offsets would require a version-2 pack index
            let offset = u32::try_from(offset)
                .map_err(|_| GitError::InvalidObjectInfo(format!("Packfile is too large")))
                .unwrap();
        }
        
        // CheckSum sha-1
        let _id: [u8; 20] = utils::read_bytes(&mut pack_file).unwrap();
        _pack.signature = Hash::from_row(&_id[..]);
        print!("{}",cache.by_hash.len());
        Ok(_pack)
    }
    /// ## Decode all `.pack` file in a dir
    /// For Example :`.git/object/pack`
    /// This function is different from the `Pack::decode` function , which in the "pack/mod.rs" 
    /// and only decode the single `.pack` file
    #[allow(unused)]
    pub fn multi_decode(root:&str) -> Result<Self, GitError>{ 

        let mut total_pack = Self::default();
        total_pack.number_of_objects=0;
        let (files,hash_vec) = utils::find_all_pack_file(root);
        let mut pack_vec = vec![];
        for _file_ in files.iter(){
            let mut _pack = Pack::default();
            _pack.pack_file = _file_.clone();
            pack_vec.push(_pack);
        }
        pack_vec.sort();
        let mut cache = PackObjectCache::default();
        for  _pack_ in pack_vec.iter_mut() {
            _pack_.decode_with_cache(&mut cache)?;
            total_pack.number_of_objects+=_pack_.number_of_objects;
        }
        total_pack.result = Arc::new(cache);
        Ok(total_pack)
    }


}

#[cfg(test)]
pub mod test{
    use crate::git::pack::Pack;

    #[test]
    fn test_multi_pack_decode(){
        Pack::multi_decode("./resources./friger").unwrap();
    }
}